﻿using S7.Net;
using System.Net.Sockets;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;

namespace SimS7Study
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : Window
    {
        Socket socket = new Socket(SocketType.Stream, ProtocolType.Tcp);

        public MainWindow()
        {
            InitializeComponent();
        }

        /// <summary>
        /// 连接第三方库
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click(object sender, RoutedEventArgs e)
        {

            // 机架号 标识plc系统中的主框架(安装有CPU的机架就是主框架,主框架的机架号就是0)或扩展框架(其他扩展框架，如果有多个从1开始依次往后推)。
            // 槽口号 分配CPU模块、电源模块、IO信号模块、通信模块等的具体位置。槽号确定的是设备的唯一性,确保每个模块在机架号的位置明确。
            Plc plc = new Plc(CpuType.S71500, "192.168.109.30", 0, 0);

            plc.Open();

            // 从db1 第二个开始读4个字节
            byte[] bytes = plc.ReadBytes(DataType.DataBlock, 1, 2, 4);



        }

        /// <summary>
        /// 连接-手搓协议
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_1(object sender, RoutedEventArgs e)
        {
            Connect();
        }

        /// <summary>
        /// 建立连接
        /// </summary>
        private void Connect()
        {
            #region 三次握手
            socket.Connect("192.168.109.30", 102);
            #endregion

            #region COTP连接

            byte[] bytes = [
                 #region TPKT
                0x03,//版本号
                0x00,//保留

                0x00,//长度
                0x16,
                  #endregion

                 #region COTP
                0x11,//该字节之后的所有字节数
                0xe0,//PDU类型   附录一

                0x00,//目标引用
                0x00,

                0x00,//源引用
                0x01,

                0x00,//扩展格式

                0xc1,
                0x02,//原tsap长度
                0x01,//源连接模式。附录二
                0x00,//机架号 槽口号

                0xc2,
                0x02,
                0x03,//目标连接模式
                0x00,//机架号 槽口号 

                0xc0,
                0x01,
                0x0a//2的10次方
	            #endregion
            ];

            socket.Send(bytes);
            #endregion

            #region setup communication的报文
            bytes = [
                #region TPKT
                 0x03,//版本号
                0x00,//保留

                0x00,//长度
                0x19,
                #endregion

                #region COTP
                    0x02,//当前cotp后面的字节数
                    0xf0,//pdu类型
                    0x80,//固定
                #endregion

                #region S7 Communication-header
                    0x32,//协议ID 固定

                    0x01,//远程操作命令 附录三

                    0x00,//预留
                    0x00,

                    0xff,// 协议单元事件引用 累加
                    0xff,

                    0x00,//参数长度
                    0x08,

                    0x00,//数据长度
                    0x00,
                #endregion

                #region  S7 Communication-parameter
                    0xf0,//功能码。通信功能是f0。附录四
                    0x00,//预留

                    0x00,//amq(calling)
                    0x03,

                    0x00,//amq(called)
                    0x03,

                    0x03,//pdu长度
                    0xc0
               #endregion
            ];
            #endregion

            socket.Send(bytes);
        }

        /// <summary>
        /// 手搓协议 读字节(从第2个字节开始读4个字节)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_2(object sender, RoutedEventArgs e)
        {
            Connect();//先连接

            byte[] readBytes = [
                #region TPKT
                    0x03,//版本号
                    0x00,//预留

                    0x00,//整个报文长度  以后需要计算
                    0x1f,
                #endregion

                #region COTP
                    0x02,
                    0xf0,
                    0x80,
                #endregion

                #region S7 communication-header
                    0x32,
                    0x01,

                    0x00,
                    0x00,
                    0x00,
                    0x00,

                    0x00,
                    0x0e,//parameter的长度。以后需要计算

                    0x00,
                    0x00,
                #endregion

                #region S7 communication-Parameter
                    0x04,//读变量04。附录四
                    0x01,//读几项 。以后需要计算

                #region Item1的参数信息
                    0x12,//固定值
                    0x0a,//item1之后的字节数
                    0x10,//固定
                    0x02,//parameter数据类型。附录八

                    0x00,//个数
                    0x04,

                    0x00,//db编号
                    0x01,

                    0x84,//84 db。附录十

                 //读的起始地址(从哪个字节开始+哪个位开始)
                 //从第2个字节开始 从第2个字节+第0位开始 0-7
                 //0000 0000 0000 0000 0001 0000
                 0x00,
                 0x00,
                 0x10,
                 //Q1.5
                 //0000 0000 0000 0000  0000 1101 //00 00 0d
                 //Q2.4
                 //0000 0000 0000 0000 0001 0100 //00 00 14
                #endregion
                 ];

            #endregion

            socket.Send(readBytes);
        }

        /// <summary>
        /// 读多项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_3(object sender, RoutedEventArgs e)
        {
            //1、读字节(从第2个字节开始读4个字节)
            //2、Q1.5

            //加了一个Item 需要修改:1、parameter项数 2、header里面采纳数长度 3、报文总长度
            Connect();//先连接

            byte[] readBytes = [
                #region TPKT
                    0x03,//版本号
                    0x00,//预留

                    0x00,//整个报文长度  以后需要计算
                    0x43,//31+12=43+12=55+12=67
                #endregion

                #region COTP
                    0x02,
                    0xf0,
                    0x80,
                #endregion

                #region S7 communication-header
                    0x32,
                    0x01,

                    0x00,
                    0x00,
                    0x00,
                    0x00,

                    0x00,
                    0x32,//parameter的长度。以后需要计算  14+12=26+12=38+12=50

                    0x00,
                    0x00,
                #endregion

                #region S7 communication-Parameter
                    0x04,//读变量04。附录四
                    0x04,//读几项 。以后需要计算

                #region Item1的参数信息  1、读字节(从第2个字节开始读4个字节)
                    0x12,//固定值
                    0x0a,//item1之后的字节数
                    0x10,//固定
                    0x02,//parameter数据类型。附录八

                    0x00,//个数
                    0x04,

                    0x00,//db编号
                    0x01,

                    0x84,//84 db。附录十

                 //读的起始地址(从哪个字节开始+哪个位开始)
                 //从第2个字节开始 从第2个字节+第0位开始 0-7
                 //0000 0000 0000 0000 0001 0000
                 0x00,
                 0x00,
                 0x10,
                //Q1.5
                //0000 0000 0000 0000  0000 1101 //00 00 0d
                //Q2.4
                //0000 0000 0000 0000 0001 0100 //00 00 14
                #endregion

                #region Item2的参数信息 Q1.5
                    0x12,//固定值
                    0x0a,//item2之后的字节数
                    0x10,//固定
                    0x01,//parameter数据类型。附录八

                    0x00,//个数
                    0x01,

                    0x00,//db编号  如果读的不是db，则写0x0000
                    0x00,

                    0x82,//82 Q区。附录十

                     //0000 0000 0000 0000 0000 1101
                     0x00,
                     0x00,
                     0x0d,
	            #endregion

                 #region Item3的参数信息 Q1.6
                    0x12,//固定值
                    0x0a,//item2之后的字节数
                    0x10,//固定
                    0x01,//parameter数据类型。附录八

                    0x00,//个数
                    0x01,

                    0x00,//db编号  如果读的不是db，则写0x0000
                    0x00,

                    0x82,//82 Q区。附录十

                     //0000 0000 0000 0000 0000 1110
                     0x00,
                     0x00,
                     0x0e,
	            #endregion

                     #region Item4的参数信息  1、db区的0.1
                    0x12,//固定值
                    0x0a,//item1之后的字节数
                    0x10,//固定
                    0x01,//parameter数据类型。附录八

                    0x00,//个数
                    0x01,

                    0x00,//db编号
                    0x01,

                    0x84,//84 db。附录十

                 //读的起始地址(从哪个字节开始+哪个位开始)
                 //从第2个字节开始 从第2个字节+第0位开始 0-7
                 //0000 0000 0000 0000 0000 0 001
                 0x00,
                 0x00,
                 0x01,
                //Q1.5
                //0000 0000 0000 0000  0000 1101 //00 00 0d
                //Q2.4
                //0000 0000 0000 0000 0001 0100 //00 00 14
                #endregion
                #endregion
            ];

            socket.Send(readBytes);
        }

        /// <summary>
        /// 调用第三方写
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_4(object sender, RoutedEventArgs e)
        {
            Plc plc = new Plc(CpuType.S71500, "192.168.109.30", 0, 0);

            plc.Open();

            // 向第2个字节写数字234
            uint val = 234;
            byte[] bytes = BitConverter.GetBytes(val).Reverse().ToArray(); // 西门子PLC是大端模式  C#是小端模式

            plc.WriteBytes(DataType.DataBlock, 1, 2, bytes);

        }

        /// <summary>
        /// 写单项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_5(object sender, RoutedEventArgs e)
        {
            //向第2个字节写数字234 [0x00,0x00,0x00,0xea]
            Connect();//先连接

            byte[] bytes = [
                #region TPKT
                0x03,//0
                0x00,//1

                0x00,//2
                0x27,//3
                #endregion

                #region COTP
                0x02,//4
                0xf0,//5
                0x80,//6
                #endregion

                #region S7-Header
                    0x32,//7
                    0x01,//8

                    0x00,//9
                    0x00,//10

                    0x00,//11
                    0x03,//12

                    0x00,//13  参数长度
                    0x0e,//14

                    0x00,//15 数据长度
                    0x08,//16 
                #endregion

                #region S7-Parameter
                 0x05,//17 功能码 05表示write
                 0x01,//18 写多少项
                        #region Item1的参数
                         0x12,//19 固定
                         0x0a,//20 item1之后的字节数
                         0x10,//21 固定
                         0x02,//22 byte

                         0x00,//23
                         0x04,//24

                         0x00,//25
                         0x01,//26

                         0x84,//27  84表示db

                         //写数据的起始地址
                         //0000 0000  0000 0000 0001 0000
                         0x00,//28
                         0x00,//29
                         0x10,//30
                    #endregion
                #endregion

                #region S7-data
                    #region Item1的数据
                         0x00,//31 固定
                         0x04,//32 byte/word/dword 都是04
                         0x00,//33
                         0x20,//34 位数

                         0x00,//35
                         0x00,//36
                         0x00,//37 
                         0xea,//38
                 #endregion
                #endregion
            ];

            socket.Send(bytes);
        }

        /// <summary>
        /// 写多项
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Button_Click_6(object sender, RoutedEventArgs e)
        {
            //向第2个字节写数字234 [0x00,0x00,0x00,0xea]
            Connect();//先连接

            //1、总长度  2、s7-header 参数总长度、数据长度 3、参数 多少项 加Item、数据加Item
            byte[] bytes = [
                #region TPKT
                0x03,//0
                0x00,//1

                0x00,//2
                0x4a,//3 39+17=56+17=73+1=74
                #endregion

                #region COTP
                0x02,//4
                0xf0,//5
                0x80,//6
                #endregion

                #region S7-Header
                    0x32,//7
                    0x01,//8

                    0x00,//9
                    0x00,//10

                    0x00,//11
                    0x03,//12

                    0x00,//13  参数长度
                    0x26,//14   14+12=26+12=38

                    0x00,//15 数据长度
                    0x13,//16 8+5=13+5+1=19
                #endregion

                #region S7-Parameter
                         0x05,//17 功能码 05表示write
                         0x03,//18 写多少项
                        #region Item1的参数
                         0x12,//19 固定
                         0x0a,//20 item1之后的字节数
                         0x10,//21 固定
                         0x02,//22 byte

                         0x00,//23
                         0x04,//24

                         0x00,//25
                         0x01,//26

                         0x84,//27  84表示db

                         //写数据的起始地址
                         //0000 0000  0000 0000 0001 0000
                         0x00,//28
                         0x00,//29
                         0x10,//30
                    #endregion

                        #region Item2的参数 Q1.5 写成true
                         0x12,//固定
                         0x0a,//item2之后的字节数
                         0x10,//固定
                         0x01,//bit

                         0x00,//
                         0x01,//

                         0x00,//
                         0x00,//

                         0x82,//  82表示Q区

                         //写数据的起始地址
                         //0000 0000  0000 0000 0000 1101
                         0x00,//
                         0x00,//
                         0x0d,//
                    #endregion

                        #region Item3的参数 Q1.7 写成true
                         0x12,//固定
                         0x0a,//item2之后的字节数
                         0x10,//固定
                         0x01,//bit

                         0x00,//
                         0x01,//

                         0x00,//
                         0x00,//

                         0x82,//  82表示Q区

                         //写数据的起始地址
                         //0000 0000  0000 0000 0000 1111
                         0x00,//
                         0x00,//
                         0x0f,//
                    #endregion
                #endregion

                #region S7-data
                    #region Item1的数据
                         0x00,//31 固定
                         0x04,//32 byte/word/dword 都是04
                         0x00,//33
                         0x20,//34 位数

                         0x00,//35
                         0x00,//36
                         0x00,//37 
                         0xea,//38
                 #endregion
                        
                    #region Item2的数据 Q1.5 写成true
                         0x00,// 固定
                         0x03,//  bit是03
                         0x00,//
                         0x01,// 位数

                         0x01,
                         0x00,//填充字节  奇数长度且不是最后一项就要填充字节
                 #endregion

                    #region Item3的数据 Q1.7 写成true
                         0x00,// 固定
                         0x03,//  bit是03
                         0x00,//
                         0x01,// 位数

                         0x01,
                 #endregion
                #endregion
            ];

            socket.Send(bytes);
        }
    }
}